#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time   : 2023-09-11 20:18
# @Author : hard work
# @File    : l2_traffic_util.py
# @Description :
from stc_utils.py_util.stc_based import Stc_global
from stc_utils.py_util.stc_cfgs import stc_cfg

"""
Create_l2_traffic 继承于 Stc_global，在此之上，拓展L2层流的属性

参数说明：
    见init_l2_traffic()函数
    
函数说明：
    必须先初始化父类Stc_global
    init_l2_traffic()   初始化变量，根据调用不同的函数传递不同的值，必须先初始化此方法
    create_ethII_flow() 创建EthernetII的流，需要在init_l2_traffic()中传入srcMac，dstMac，frameSize等参数
    create_l2_vid_tag() 创建EthernetII带VLAN tag的流，需要先调用create_ethII_flow()，并在init_l2_traffic()传输vid
    create_dstMac_auto() 创建目的MAC自动增长的EthernetII的流，需要先调用create_ethII_flow()，可选create_l2_vid_tag()
    create_srcMac_auto() 创建源MAC自动增长的EthernetII的流，需要先调用create_ethII_flow()，可选create_l2_vid_tag()
    set_traffic_ger_ana_burst() 设置发包模式为burst和收包
    set_traffic_ger_ana_load() hard work on programming ...
    
调用过程：
    # 初始化
    stc_Chassis_addr = stc_cfg.stc_Chassis_addr  # 思博伦STC的ip地址，如：10.11.0.247
    slot = stc_cfg.slot                          # 思博伦的槽位 如：1
    port_A = stc_cfg.port_A                      # 思博伦的port 如：14 
    port_B = stc_cfg.port_B                      # 思博伦的port 如：15
    port_B_OB = stc_cfg.port_B_OB                # 思博伦的port 如：16 
    stc_install_path = stc_cfg.stcInstallDir     # 思博伦STC的安装路径 如："C:\stc_instal_dir"
    cls.l2 = Create_l2_traffic(stc_install_path, stc_Chassis_addr, slot, port_A, port_B) # 必须初始化父类方法
    
    # 调用方法
    l2.stc_init() # 连接思博伦，占用端口，设置log路径和命名
    self.l2.init_l2_traffic()   #l2的初始化，必须调用
    self.l2.create_ethII_flow() # 创建L2层流，参见如上#函数说明
    
    # 参见#父类Stc_global#函数说明
    self.set_traffic_ger_ana_burst 
    self.l2.set_apply()
    self.l2.set_enable_capture()
    self.l2.set_save_result_file()
    self.l2.start_flow()
    self.l2.set_flow_stop()
    self.l2.set_save_capture_result_file()
    self.l2.set_stc_destroy()    
        
"""


class Create_l2_traffic(Stc_global):

    def __init__(self, stcInstallDir, stc_Chassis_addr, slot, port_TX, port_RX, port_RX_OB,port_RX_20,port_RX_16):
        super().__init__(stcInstallDir, stc_Chassis_addr, slot, port_TX, port_RX, port_RX_OB,port_RX_20,port_RX_16)


        """
        param : frameSize  packet length
        param : srcMac  source mac address
        param : dstMac  destination mac address
        param : BURSTS  [BURSTS, continue, ..], 现在只有burst模式
        param : BurstSize  burst packet size
        param : Duration   traffic count 发包个数
        param : FixedLoad  traffic load 未实现
        param : vid        vlan tag
        param : dstMac_pkt_cnt    dstMac auto increase
        param : srcMac_pkt_cnt    srcMac auto increase
        """
        self.hVlan = None
        self.hEthernet = None
        self.hStreamBlock = None
        self.srcMac_pkt_cnt = None
        self.dstMac_pkt_cnt = None
        self.FixedLoad = None
        self.Duration = None
        self.BurstSize = None
        self.BURSTS = None
        self.frameSize = None
        self.dstMac = None
        self.srcMac = None
        self.vid = None
        self.type = None
        self.prio = None
        self.hGeneratorConfig = None
        self.CrcError = None
        self.DurationMode = None

    def create_ethII_flow(self, dicts):
        if dicts:

            self.srcMac = dicts['srcMac']
            self.dstMac = dicts['dstMac']
            self.frameSize = dicts['frameSize']
            self.BURSTS = dicts["BURSTS"]
            self.BurstSize = dicts["BurstSize"]
            self.Duration = dicts["Duration"]
            self.FixedLoad = dicts["FixedLoad"]

        else:

            self.srcMac = "00:00:20:00:00:00"
            self.dstMac = "00:00:01:00:00:01"
            self.frameSize = 128
            self.BURSTS = "BURSTS"
            self.BurstSize = 1
            self.Duration = 100
            self.FixedLoad = 100

        # 建流
        # Create a stream block.
        print("Configuring stream block ...")
        self.hStreamBlock = self.stc.create("streamBlock", under=self.hPortTx, insertSig=True, frameConfig="",
                                            frameLengthMode="FIXED",
                                            maxFrameLength=1200, FixedFrameLength=self.frameSize)

        # Add an EthernetII Protocol Data Unit (PDU).
        print("Adding headers")
        self.hEthernet = self.stc.create("ethernet:EthernetII", under=self.hStreamBlock, name="sb1_eth",
                                         srcMac=self.srcMac,
                                         dstMac=self.dstMac)

    def create_StreamBlock(self,dicts,vid_dicts):
        """don't use this"""
        if dicts:

            self.srcMac = dicts['srcMac']
            self.dstMac = dicts['dstMac']
            self.frameSize = dicts['frameSize']
            self.BURSTS = dicts["BURSTS"]
            self.BurstSize = dicts["BurstSize"]
            self.Duration = dicts["Duration"]
            self.FixedLoad = dicts["FixedLoad"]

        else:

            self.srcMac = "00:00:20:00:00:00"
            self.dstMac = "00:00:01:00:00:01"
            self.frameSize = 128
            self.BURSTS = "BURSTS"
            self.BurstSize = 1
            self.Duration = 100
            self.FixedLoad = 100
        if "vid" in vid_dicts:
            self.vid = vid_dicts['vid']
            self.type = vid_dicts['type']
            self.prio = vid_dicts['prio']
        else:
            self.vid = 0
            self.type = '8100'
            self.prio = '000'
        # 建流
        # Create a stream block.
        print("Configuring stream block ...")
        self.hStreamBlock = self.stc.create("streamBlock", under=self.hPortTx, insertSig=True, frameConfig="",
                                            frameLengthMode="FIXED",
                                            maxFrameLength=1200, FixedFrameLength=self.frameSize)

        # self.StreamBlock_1 = self.stc.create("streamBlock", under=self.hPortTx,insertSig=True,frameConfig=r"<frame><config><pdus><pdu name=\"eth1\" pdu=\"ethernet:EthernetII\"><dstMac>01:0C:CD:01:01:01</dstMac><srcMac>00:10:94:00:00:40</srcMac><etherType override=\"true\" >88B5</etherType><vlans name=\"anon_6939\"><Vlan name=\"Vlan\"><pri>000</pri><id>0</id></Vlan></vlans></pdu></pdus></config></frame>",
        #                                 FrameLengthMode="FIXED",
        #                                 maxFrameLength=1200,
        #                                 FixedFrameLength=256,
        #                                 )
        # Add an EthernetII Protocol Data Unit (PDU).
        print("Adding headers")
        self.hEthernet = self.stc.create("ethernet:EthernetII",
                                         under=self.hStreamBlock,
                                         name="sb1_eth",
                                         srcMac='00:10:94:00:00:40',
                                         dstMac='01:0C:CD:01:01:01')
        self.hVlan = self.stc.create("vlans", under=self.hEthernet)
        vlanValue = self.stc.create("vlan", under=self.hVlan, id=self.vid, type=self.type, pri=self.prio)

        RangeModifier_1 = self.stc.create("RangeModifier",
                                     under=self.hStreamBlock,
                                     ModifierMode="INCR",
                                     Mask="4095",
                                     StepValue="1",
                                     RecycleCount="4094",
                                     RepeatCount="0",
                                     Data="0",
                                     DataType="NATIVE",
                                     EnableStream="True",
                                     Offset="0",
                                     OffsetReference="sb1_eth.vlans.vlan.id",
                                     Active="TRUE",
                                     LocalActive="TRUE",
                                     Name="Modifier")

    def create_ethII_flow_CRCERROR(self, dicts):
        if dicts:
            # print("如果传入的参数不为空")
            self.srcMac = dicts['srcMac']
            self.dstMac = dicts['dstMac']
            self.frameSize = dicts['frameSize']
            self.BURSTS = dicts["BURSTS"]
            self.BurstSize = dicts["BurstSize"]
            self.Duration = dicts["Duration"]
            self.FixedLoad = dicts["FixedLoad"]
            self.CrcError = dicts['CrcError']
        else:
            print("use default value")
            self.srcMac = "00:00:20:00:00:00"
            self.dstMac = "00:00:01:00:00:01"
            self.frameSize = 128
            self.BURSTS = "BURSTS"
            self.BurstSize = 1
            self.Duration = 100
            self.FixedLoad = 100
            self.CrcError = True

        # 建流
        # Create a stream block.
        print("Configuring stream block ...")
        self.hStreamBlock = self.stc.create("streamBlock", under=self.hPortTx, insertSig=True, frameConfig="",
                                            frameLengthMode="FIXED",
                                            maxFrameLength=1200, FixedFrameLength=self.frameSize,InsertFcs=self.CrcError)

        # Add an EthernetII Protocol Data Unit (PDU).
        print("Adding headers")
        self.hEthernet = self.stc.create("ethernet:EthernetII", under=self.hStreamBlock, name="sb1_eth",
                                         srcMac=self.srcMac,
                                         dstMac=self.dstMac)

    def create_l2_vid_tag(self, vid_dicts):
        if "vid" in vid_dicts:
            self.vid = vid_dicts['vid']
            self.type = vid_dicts['type']
            self.prio = vid_dicts['prio']
        else:
            self.vid = 0
            self.type = '8100'
            self.prio = '000'
        self.hVlan = self.stc.create("vlans", under=self.hEthernet)
        vlanValue = self.stc.create("vlan", under=self.hVlan, id=self.vid, type=self.type, pri=self.prio)

    def create_dstMac_auto(self,dstMac_pkt_cnt:int):
        # if "dstMac_pkt_cnt" in dicts.keys():
        #     self.dstMac_pkt_cnt = dicts["dstMac_pkt_cnt"]
        # else:
        #     self.dstMac_pkt_cnt = 100
        hRangeModifier = self.stc.create("RangeModifier",
                                         under=self.hStreamBlock,
                                         ModifierMode="INCR",
                                         # ModifierMode="DECR", # 倒序
                                         Mask="00:00:FF:FF:FF:FF",
                                         StepValue="00:00:00:00:00:01",
                                         Data=self.dstMac,
                                         # RecycleCount=4096, # 反转
                                         RecycleCount=dstMac_pkt_cnt,  # 反转
                                         RepeatCount=0,
                                         DataType="NATIVE",
                                         EnableStream=True,
                                         Offset=0,
                                         OffsetReference="sb1_eth.dstMac")

    def create_srcMac_auto(self,srcMac_pkt_cnt:int):
        # if "srcMac_pkt_cnt" in dicts:
        #     self.srcMac_pkt_cnt = dicts["srcMac_pkt_cnt"]
        # else:
        #     self.srcMac_pkt_cnt = 100
        hRangeModifier1 = self.stc.create("RangeModifier",
                                          under=self.hStreamBlock,
                                          ModifierMode="INCR",
                                          Mask="00:00:FF:FF:FF:FF",
                                          StepValue="00:00:00:00:00:01",
                                          Data=self.srcMac,
                                          # RecycleCount=200,
                                          RecycleCount=srcMac_pkt_cnt,
                                          RepeatCount=0,
                                          DataType="NATIVE",
                                          EnableStream=True,
                                          Offset=0,
                                          OffsetReference="sb1_eth.srcMac")

    def set_traffic_ger_ana_burst(self):
        # Configure generator.
        print("Configuring Generator")
        self.hGeneratorConfig = self.stc.get(self.hGenerator, "children-GeneratorConfig")

        self.stc.config(self.hGeneratorConfig,
                        DurationMode=self.BURSTS,
                        BurstSize=self.BurstSize,
                        Duration=self.Duration, # 发包个数
                        LoadMode="FIXED",
                        FixedLoad=self.FixedLoad,
                        LoadUnit="PERCENT_LINE_RATE",
                        SchedulingMode="PORT_BASED")

        # Analyzer Configuration.
        print("Configuring Analyzer")
        hAnalyzerConfig = self.stc.get(self.hAnalyzer, "children-AnalyzerConfig")
        # hAnalyzerConfig_OB = self.stc.get(self.hAnalyzer_OB, "children-AnalyzerConfig")
        # Subscribe to realtime results.
        print("Subscribe to results")
        self.hAnaResults = self.stc.subscribe(Parent=self.hProject,
                                              ConfigType="Analyzer",
                                              resulttype="AnalyzerPortResults",
                                              filenameprefix="Analyzer_%s_Results" % self.hPortRx)

        # self.hAnalyzer_OB = self.stc.subscribe(Parent=self.hProject,
        #                                        ConfigType="Analyzer",
        #                                        resulttype="AnalyzerPortResults",
        #                                        filenameprefix="Analyzer_%s_Result" % self.hPortRx_OB)

        self.hGenResults = self.stc.subscribe(Parent=self.hProject,
                                              ConfigType="Generator",
                                              resulttype="GeneratorPortResults",
                                              filenameprefix="Generator_%s_Counter" % self.hPortTx,
                                              Interval=2)

    def set_traffic_ger_ana_load(self, load_dict):
        if load_dict:
            self.Duration = load_dict['Duration']
            self.DurationMode = load_dict['DurationMode']
            self.FixedLoad = load_dict['FixedLoad']
        else:
            self.Duration = 100
            self.DurationMode = 'CONTINUOUS'
            self.FixedLoad = 100

        # Configure generator.
        print("Configuring Generator")
        self.hGeneratorConfig = self.stc.get(self.hGenerator, "children-GeneratorConfig")

        self.stc.config(self.hGeneratorConfig,
                        SchedulingMode="RATE_BASED",
                        Duration=self.Duration,
                        DurationMode=self.DurationMode,
                        BurstSize="1",
                        LoadUnit="PERCENT_LINE_RATE",
                        LoadMode="FIXED",
                        FixedLoad=self.FixedLoad,
                        )

        # Analyzer Configuration.
        print("Configuring Analyzer")
        hAnalyzerConfig = self.stc.get(self.hAnalyzer, "children-AnalyzerConfig")
        # hAnalyzerConfig_OB = self.stc.get(self.hAnalyzer_OB, "children-AnalyzerConfig")
        # Subscribe to realtime results.
        print("Subscribe to results")
        self.hAnaResults = self.stc.subscribe(Parent=self.hProject,
                                              ConfigType="Analyzer",
                                              resulttype="AnalyzerPortResults",
                                              filenameprefix="Analyzer_%s_Results" % self.hPortRx)

        # self.hAnalyzer_OB = self.stc.subscribe(Parent=self.hProject,
        #                                        ConfigType="Analyzer",
        #                                        resulttype="AnalyzerPortResults",
        #                                        filenameprefix="Analyzer_%s_Result" % self.hPortRx_OB)

        self.hGenResults = self.stc.subscribe(Parent=self.hProject,
                                              ConfigType="Generator",
                                              resulttype="GeneratorPortResults",
                                              filenameprefix="Generator_%s_Counter" % self.hPortTx,
                                              Interval=2)

if __name__ == '__main__':

    stc_Chassis_addr = stc_cfg.stc_Chassis_addr
    slot = stc_cfg.slot
    port_A = stc_cfg.port_A
    port_B = stc_cfg.port_B
    port_B_OB = stc_cfg.port_B_OB
    port_20 = stc_cfg.port_20
    port_16 = stc_cfg.port_16
    stc_install_path = stc_cfg.stcInstallDir
    l2 = Create_l2_traffic(stc_install_path, stc_Chassis_addr, slot, port_A, port_B, port_B_OB, port_20,
                                port_16)
    # 建流
    l2.stc_init()
    arg_dict = {"srcMac": "00:00:20:00:00:00",
                "dstMac": "00:00:01:00:00:01",
                "frameSize": 128,
                "BURSTS": "BURSTS",
                "BurstSize": 1,
                "Duration": 4094,
                "FixedLoad": 10
                }
    # l2.create_ethII_flow(arg_dict)

    vid_dicts = {
        'vid': 1,
        'type': 8100,
        'prio': 000
    }
    l2.create_StreamBlock(arg_dict,vid_dicts)
    # l2.create_l2_vid_tag(vid_dicts)
    # l2.create_vid_tag_auto()
    l2.set_traffic_ger_ana_burst()
    # load_dict = {
    #     'Duration':10,
    #     'DurationMode':'CONTINUOUS',
    #     'FixedLoad': 100
    # }
    # l2.set_traffic_ger_ana_load(load_dict)
    l2.set_apply()
    l2.set_enable_capture()
    l2.set_save_result_file()
    l2.start_flow()
    l2.set_flow_stop()
    l2.set_save_capture_result_file()
    l2.set_stc_destroy()
